package com.jeremyfeinstein.utils.NetUtils;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.jeremyfeinstein.utils.Network;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

/**
 * @author : lishan
 * @e-mail : cnlishan@163.com
 * @date : 2021/2/7 10:06 AM
 * @desc :
 */
public abstract class SGRequest<T, R extends SGRequest> {
    private static Handler mDelivery;
    private static ThreadPoolExecutor threadPool;

    /**
     * 请求地址
     */
    protected String mUrl;
    /**
     * 请求头
     */
    protected HashMap<String, String> mHeaders = new HashMap<>();
    /**
     * 请求参数
     */
    protected HashMap<String, Object> mParams = new HashMap<>();
    private Type mType;

    public SGRequest(String url) {
        mUrl = url;
        mDelivery = new Handler(Looper.getMainLooper());
        threadPool = createThreadPool();
    }

    public static void runOnBackThread(Runnable runnable) {
        if (threadPool == null) {
            threadPool = createThreadPool();
        }
        threadPool.execute(runnable);
    }

    private static ThreadPoolExecutor createThreadPool() {
        return new ThreadPoolExecutor(5,
                5,
                5000,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }


    public R responseType(Type type) {
        mType = type;
        return (R) this;
    }

    public R responseType(Class claz) {
        mType = claz;
        return (R) this;
    }

    public R addHeader(String key, String value) {
        mHeaders.put(key, value);
        return (R) this;
    }

    public R addParam(String key, Object value) {
        if (value == null) {
            return (R) this;
        }
        //int byte char short long double float boolean 和他们的包装类型，但是除了 String.class 所以要额外判断
        try {
            if (value.getClass() == String.class) {
                mParams.put(key, value);
            } else {
                Field field = value.getClass().getField("TYPE");
                Class claz = (Class) field.get(null);
                if (claz.isPrimitive()) {
                    mParams.put(key, value);
                }
            }
            //} catch (NoSuchFieldException | IllegalAccessException e) {
        } catch (Exception e) {
            e.printStackTrace();
        }

        return (R) this;
    }

    public void post(final JsonCallback callback) {

        if (!Network.isAvailable(AppGlobals.getApplication())) {
            ApiResponse<T> apiResponse = new ApiResponse<>();
            apiResponse.message = "当前无网络可用";
            callback.onError(apiResponse);
            return;
        }

        runOnBackThread(new Runnable() {
            @Override
            public void run() {
                Call call = getCall();
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        sendFailResultCallback(e, callback);
                    }

                    @Override
                    public void onResponse(Call call, Response response) {
                        ApiResponse<T> apiResponse = parseResponse(response, callback);
                        sendSuccessResultCallback(apiResponse, callback);
                    }
                });
            }
        });

    }

    private Call getCall() {
        okhttp3.Request.Builder builder = new okhttp3.Request.Builder();
        addHeaders(builder);
        okhttp3.Request request = generateRequest(builder);
        return SGApiService.okHttpClient.newCall(request);
    }

    protected abstract okhttp3.Request generateRequest(okhttp3.Request.Builder builder);

    private void addHeaders(okhttp3.Request.Builder builder) {
        for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
            if (!TextUtils.isEmpty(entry.getKey()) && !TextUtils.isEmpty(entry.getValue())) {
                Log.e("TAG", "addHeaders: Key: " + entry.getKey());
                Log.e("TAG", "addHeaders: Value: " + entry.getValue());
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    private ApiResponse<T> parseResponse(Response response, JsonCallback callback) {
        String message = null;
        int status = response.code();
        boolean success = response.isSuccessful();
        ApiResponse<T> result = new ApiResponse<>();
        Convert convert;
        if (SGApiService.sConvert == null) {
            convert = new SGJsonConvert();
        } else {
            convert = SGApiService.sConvert;
        }

        try {
            String content = response.body().string();
            if (success) {
                if (callback != null) {
                    ParameterizedType type = (ParameterizedType) callback.getClass().getGenericSuperclass();
                    Type argument = type.getActualTypeArguments()[0];
                    result.body = (T) convert.convert(content, argument);
                } else if (mType != null) {
                    result.body = (T) convert.convert(content, mType);
                } else {
                    Log.e("request", "parseResponse: 无法解析 ");
                }
            } else {
                message = content;
            }
        } catch (Exception e) {
            message = e.getMessage();
            success = false;
            status = 0;
        }
        result.success = success;
        result.status = status;
        result.message = message;

        return result;
    }


    private void sendSuccessResultCallback(final ApiResponse<T> apiResponse, final JsonCallback callback) {
        if (callback == null) return;
        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                if (!apiResponse.success) {
                    callback.onError(apiResponse);
                } else {
                    callback.onSuccess(apiResponse);
                }
            }
        });
    }


    private void sendFailResultCallback(final Exception e, final JsonCallback callback) {
        if (callback == null) return;

        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                ApiResponse<T> apiResponse = new ApiResponse<>();
                apiResponse.message = e.getMessage();
                callback.onError(apiResponse);
            }
        });
    }

}
